Tumor evolution project

Data used

In this notebook, we are using the pbta.tsv file geenrated by the sample-distribution-analysis module.

Set up

suppressPackageStartupMessages({
  library(tidyverse)
  library(rstatix)
  library(ggpubr)
})

Directories and File Inputs/Outputs

# Detect the ".git" folder -- this will be in the project root directory
# Use this as the root directory to ensure proper sourcing of functions 
# no matter where this is called from
root_dir <- rprojroot::find_root(rprojroot::has_dir(".git"))
analysis_dir <- file.path(root_dir, "analyses", "tmb-vaf-longitudinal")
input_dir <- file.path(analysis_dir, "input")
files_dir <- file.path(root_dir, "analyses", "sample-distribution-analysis", "results")

# Input files
pbta_file <- file.path(files_dir, "pbta.tsv") # file from add-sample-distribution module
tmb_file <- file.path(input_dir, "snv-mutation-tmb-coding.tsv")
palette_file <- file.path(root_dir, "figures", "palettes", "tumor_descriptor_color_palette.tsv")

# File path to plot directory
plots_dir <-
  file.path(analysis_dir, "plots")
if (!dir.exists(plots_dir)) {
  dir.create(plots_dir)
}

source(paste0(root_dir, "/figures/scripts/theme.R"))

Read in data and process

# Make this reproducible
set.seed(2023)

# Read in tmb file and remove hypermutant samples
tmb <- readr::read_tsv(tmb_file, guess_max = 100000, show_col_types = FALSE) %>%
  filter(!tmb >= 10) %>% 
  dplyr::rename(Kids_First_Biospecimen_ID = Tumor_Sample_Barcode) # change name of the biospecimen to match the one from the histologies files

# Read in pbta file and create df
df <- readr::read_tsv(pbta_file, guess_max = 100000, show_col_types = FALSE) %>%
  filter(!(experimental_strategy == "RNA-Seq"),
         !(tumor_descriptor == "Unavailable")) %>% # these are 2 samples
  left_join(tmb, by = c("Kids_First_Biospecimen_ID", "experimental_strategy")) %>%
  select(Kids_First_Participant_ID, Kids_First_Biospecimen_ID, tumor_descriptor,
         broad_histology, match_id_DNA, experimental_strategy, 
         cancer_group, short_histology, tmb, mutation_count, DNA) %>%
  dplyr:::mutate(short_histology_sum = ifelse(short_histology == "HGAT", "HGG",
                                              ifelse(short_histology == "LGAT", "LGG", 
                                                     ifelse(short_histology == "Ependymoma", "Ependymoma", 
                                                            ifelse(short_histology == "Medulloblastoma", "Medulloblastoma", 
                                                                   ifelse(short_histology == "ATRT", "ATRT", "Other"))))),
                 log10_tmb = abs(log10(tmb)),
                 tumor_descriptor = factor(tumor_descriptor),
                 tumor_descriptor = fct_relevel(tumor_descriptor, c("Diagnosis", "Progressive", "Recurrence", "Deceased", "Second Malignancy", "Unavailable"))) %>% 
  distinct(match_id_DNA, .keep_all = TRUE) %>% # keep only one bs_sample per genomic assay (WGS/WXS)
  filter(!is.na(tmb))
Warning: There was 1 warning in `dplyr:::mutate()`.
ℹ In argument: `tumor_descriptor = fct_relevel(...)`.
Caused by warning:
! 1 unknown level in `f`: Unavailable
# How many samples per Timepoint?
print(df %>% count(tumor_descriptor))

# How many samples per cancer type?
print(df %>% count(short_histology_sum))

# How many samples per Timepoint and cancer type?
rename(count(df, tumor_descriptor, short_histology_sum), Freq = n)

# How many cases with unpaired longitudinal samples?
no_samples <- length(unique(df$Kids_First_Participant_ID))

# Let's count and remove any timepoints with less than 2 samples therein
timepoint_n_df <- df %>% 
  count(tumor_descriptor) %>% 
  dplyr::mutate(tumor_descriptor_n = glue::glue("{tumor_descriptor} (N={n})")) %>% 
  dplyr::rename(timepoint_n = n)

df_plot <- df %>% 
  left_join(timepoint_n_df, by = c("tumor_descriptor")) %>%
  filter(!timepoint_n <= 2) # remove if total number of values per group is less than 2

How many patient samples in the unpaired longitudinal data?

There are 1924 samples in total.

All unpaired samples

We are interested in how TMB changes over the time in all PBTA samples (unpaired samples).

# Read color palette
palette_df <- readr::read_tsv(palette_file, guess_max = 100000, show_col_types = FALSE) %>% 
  mutate(tumor_descriptor = color_names)

# Define and order palette
palette <- palette_df$hex_codes
names(palette) <- palette_df$tumor_descriptor

# Define label for plots
Timepoint <- df_plot$tumor_descriptor

# Define ylim
ylim <- max(df_plot$tmb)
print(df_plot %>% 
        ggplot2::ggplot() + 
        ggplot2::aes(x = tumor_descriptor, 
                     y = tmb,
                     color = Timepoint) + 
        ggplot2::geom_jitter(width = 0.2, alpha = 0.5, size = 1.5) + 
        # light guiding line representing 0 exposure
        ggplot2::geom_hline(yintercept = 0, size = 0.15) + 
        ggplot2::scale_color_manual(values = palette, 
                                    breaks = sort(names(palette))) +
        ggplot2::stat_summary(color = "black", size = 0.3) + 
        ggplot2::labs(x = "Tumor descriptor",
                      y = "TMB") +
        theme_Publication() +
        scale_y_continuous(limits = c(0, ylim)) +
        theme(axis.text.x = element_text(angle = 90)))


# Save the plot
ggsave(filename = "TMB-unpaired-longitudinal-samples.pdf",
       path = plots_dir, 
       width = 10, 
       height = 5, 
       device = "pdf", 
       useDingbats = FALSE)

All unpaired samples across cancer types

We will use the short_histology column to display TMB differences across cancer types.

print(df_plot %>%
        ggplot2::ggplot() + 
        ggplot2::aes(x = tumor_descriptor, 
                     y = tmb,
                     color = Timepoint) + 
        ggplot2::geom_jitter(width = 0.2, alpha = 0.5, size = 1.5) + 
        # light guiding line representing 0 exposure
        ggplot2::geom_hline(yintercept = 0, size = 0.15) + 
        ggplot2::scale_color_manual(values = palette, 
                                    breaks = sort(names(palette))) +
        ggplot2::stat_summary(color = "black", size = 0.3) + 
        ggplot2::facet_wrap(~short_histology, nrow = 8) +
        ggplot2::labs(x = "Tumor descriptor",
                      y = "TMB") +
        theme_Publication() + 
        theme(axis.text.x = element_text(angle = 90)) +
        scale_y_continuous(limits = c(0, ylim)))


# Save the plot
ggsave(filename = "TMB-unpaired-longitudinal-samples-cancer-type.pdf", 
       path = plots_dir, 
       width = 25, 
       height = 20, 
       device = "pdf", 
       useDingbats = FALSE)

We observe that majority of samples are High- and Low-grade gliomas as well as Ependymoma, so we will classify accordingly (versus any other cancer types).

All unpaired samples across cancer types summarized

# Let's count and remove any cancer types and timepoints with less than 2 samples therein
tumor_descriptor_cancer_n_df <- df_plot %>% 
  count(short_histology_sum, tumor_descriptor) %>% 
  dplyr::mutate(tumor_descriptor_cancer_n = glue::glue("{short_histology_sum}_{tumor_descriptor}  (N={n})")) %>% 
  dplyr::rename(histology_n = n)

df_plot_cancer <- df_plot %>% 
  left_join(tumor_descriptor_cancer_n_df, by = c("tumor_descriptor", "short_histology_sum")) %>%
  filter(!histology_n <= 2) # remove if total number of values per group is less than 2

# Define label for plots
Timepoint_cancer <- df_plot_cancer$tumor_descriptor

# Define ylim
ylim_cancer <- max(df_plot_cancer$tmb)

# Plot the plot!
print(df_plot_cancer %>% 
        ggplot2::ggplot() + 
        ggplot2::aes(x = tumor_descriptor, 
                     y = tmb,
                     color = Timepoint_cancer) + 
        ggplot2::geom_jitter(width = 0.2, alpha = 0.5, size = 1.5) + 
        # light guiding line representing 0 exposure
        ggplot2::geom_hline(yintercept = 0, size = 0.15) + 
        ggplot2::scale_color_manual(values = palette, 
                                    breaks = sort(names(palette))) +
        ggplot2::stat_summary(color = "black", size = 0.3) + 
        ggplot2::facet_wrap(~short_histology_sum, nrow = 1) +
        ggplot2::labs(x = "Tumor descriptor",
                      y = "TMB") +
        theme_Publication() + 
        theme(axis.text.x = element_text(angle = 90)) +
        scale_y_continuous(limits = c(0, ylim_cancer)))


# Save the plot
ggsave(filename = "TMB-unpaired-longitudinal-samples-cancer-type-sum.pdf", 
       path = plots_dir, 
       width = 12, 
       height = 6, 
       device = "pdf", 
       useDingbats = FALSE)


# Plot by using tumor_descriptor_cancer_n
# Let's order first x axis 
#TODO: To make the f reproducible
f = c("ATRT_Diagnosis  (N=48)", "ATRT_Progressive  (N=10)", "ATRT_Recurrence  (N=3)", "ATRT_Deceased  (N=4)",
  "Ependymoma_Diagnosis  (N=113)", "Ependymoma_Progressive  (N=20)" , "Ependymoma_Recurrence  (N=24)", "Ependymoma_Deceased  (N=7)",
      "HGG_Diagnosis  (N=235)", "HGG_Progressive  (N=22)", "HGG_Recurrence  (N=15)", "HGG_Deceased  (N=72)", "HGG_Second Malignancy  (N=5)",
      "LGG_Diagnosis  (N=405)" , "LGG_Progressive  (N=61)", "LGG_Recurrence  (N=25)", "LGG_Deceased  (N=7)", "LGG_Second Malignancy  (N=4)" ,
      "Medulloblastoma_Diagnosis  (N=217)", "Medulloblastoma_Progressive  (N=6)", "Medulloblastoma_Recurrence  (N=6)" , "Medulloblastoma_Deceased  (N=6)",
      "Other_Diagnosis  (N=538)", "Other_Progressive  (N=89)", "Other_Recurrence  (N=80)", "Other_Deceased  (N=8)")

df_plot_cancer <- df_plot_cancer %>% 
  mutate(tumor_descriptor_cancer_n = factor(tumor_descriptor_cancer_n),
                 tumor_descriptor_cancer_n = fct_relevel(tumor_descriptor_cancer_n, f))
                                                         
# Plot the plot!
print(df_plot_cancer %>% 
        ggplot2::ggplot() + 
        ggplot2::aes(x = tumor_descriptor_cancer_n, 
                     y = tmb,
                     color = Timepoint_cancer) + 
        ggplot2::geom_jitter(width = 0.2, alpha = 0.5, size = 1.5) + 
        # light guiding line representing 0 exposure
        ggplot2::geom_hline(yintercept = 0, size = 0.15) + 
        ggplot2::scale_color_manual(values = palette, 
                                    breaks = sort(names(palette))) +
        ggplot2::stat_summary(color = "black", size = 0.3) + 
        ggplot2::labs(x = "Tumor descriptor",
                      y = "TMB") +
        theme_Publication() + 
        theme(axis.text.x = element_text(angle = 90)) +
        scale_y_continuous(limits = c(0, ylim_cancer)))


# Save the plot
ggsave(filename = "TMB-unpaired-longitudinal-samples-cancer-type-sum-n.pdf", 
       path = plots_dir, 
       width = 12, 
       height = 6, 
       device = "pdf", 
       useDingbats = FALSE)

#TODO: To choose one of the plots in the code chunk `plot-cancer-group-sum`

Summary statistics for Timepoints and cancer types

Considering the inequalities in the sampling effort for each timepoint, let’s explore whether the sampling size affects the observed patterns, e.g., indication of Progressive and Recurrence having higer TMB compared to Diagnosis for High-grade glioma patients.

# Inspect some random rows of the data by groups
set.seed(2023)
df_plot_cancer %>% 
  select(short_histology_sum, tumor_descriptor, tmb, log10_tmb) %>% 
  sample_n_by(short_histology_sum, tumor_descriptor, tmb, size = 1)

# Compute some summary statistics (mean and sd) by groups:
stat.summary <- df_plot_cancer %>%
  group_by(short_histology_sum, tumor_descriptor) %>%
  get_summary_stats(tmb, type = "mean_sd")
stat.summary

# Pairwise comparisons between time points at each group levels
# Paired t-test is used because we have repeated measures by time
stat.test <- df_plot_cancer %>%
  group_by(short_histology_sum) %>%
  pairwise_t_test(log10_tmb ~ tumor_descriptor, 
                  paired = FALSE, 
                  p.adjust.method = "bonferroni")
stat.test

# Add statistical test p-values
stat.test <- stat.test %>% add_xy_position(x = "tumor_descriptor")

# Create bxp
print(ggboxplot(df_plot_cancer,
                x = "tumor_descriptor",
                y = "log10_tmb",
                color = "tumor_descriptor",
                palette = palette) +
        facet_wrap(~short_histology_sum, nrow = 1) +
        theme_Publication() + 
        theme(axis.text.x = element_text(angle = 90)) +
        stat_pvalue_manual(stat.test, label = "p.adj.signif",
                           step.increase = 0.08, hide.ns = TRUE, tip.length = 0))


# Save the plot
ggsave(filename = "TMB-Bxp-stat-test.pdf", 
       path = plots_dir, 
       width = 12, 
       height = 6, 
       device = "pdf", 
       useDingbats = FALSE)


# Create jitter plot
print(df_plot_cancer %>% 
        ggplot2::ggplot() + 
        ggplot2::aes(x = tumor_descriptor, 
                     y = log10_tmb,
                     color = Timepoint_cancer) + 
        ggplot2::geom_jitter(width = 0.2, alpha = 0.5, size = 1.5) + 
        # light guiding line representing 0 exposure
        ggplot2::geom_hline(yintercept = 0, size = 0.15) +
        ggplot2::scale_color_manual(values = palette, 
                                    breaks = sort(names(palette))) +
        facet_wrap(~short_histology_sum, nrow = 1) +
        theme_Publication() + 
        theme(axis.text.x = element_text(angle = 90)) +
        stat_pvalue_manual(stat.test, label = "p.adj.signif",
                           step.increase = 0.08, hide.ns = TRUE, tip.length = 0))


# Save the plot
ggsave(filename = "TMB-jitter-stat-test.pdf", 
       path = plots_dir, 
       width = 12, 
       height = 6, 
       device = "pdf", 
       useDingbats = FALSE)

# This code was inspired by the following:
# HOW TO PERFORM MULTIPLE PAIRED T-TESTS IN R
# https://www.datanovia.com/en/blog/how-to-perform-multiple-paired-t-tests-in-r/

#TODO: To choose one of the plots in this code chunk `summary-statistics`
sessionInfo()
R version 4.2.3 (2023-03-15)
Platform: aarch64-apple-darwin20 (64-bit)
Running under: macOS Ventura 13.4.1

Matrix products: default
LAPACK: /Library/Frameworks/R.framework/Versions/4.2-arm64/Resources/lib/libRlapack.dylib

locale:
[1] en_US.UTF-8/en_US.UTF-8/en_US.UTF-8/C/en_US.UTF-8/en_US.UTF-8

attached base packages:
[1] grid      stats     graphics  grDevices utils     datasets  methods   base     

other attached packages:
 [1] ggpubr_0.6.0    rstatix_0.7.2   ggrepel_0.9.3   ggthemes_4.2.4  lubridate_1.9.2 forcats_1.0.0   stringr_1.5.0   dplyr_1.1.2    
 [9] purrr_1.0.1     readr_2.1.4     tidyr_1.3.0     tibble_3.2.1    ggplot2_3.4.2   tidyverse_2.0.0

loaded via a namespace (and not attached):
 [1] sass_0.4.7             bit64_4.0.5            vroom_1.6.3            jsonlite_1.8.7         carData_3.0-5         
 [6] R.utils_2.12.2         bslib_0.5.0            stats4_4.2.3           GenomeInfoDbData_1.2.9 yaml_2.3.7            
[11] pillar_1.9.0           backports_1.4.1        glue_1.6.2             digest_0.6.33          GenomicRanges_1.50.2  
[16] XVector_0.38.0         ggsignif_0.6.4         colorspace_2.1-0       htmltools_0.5.5        R.oo_1.25.0           
[21] pkgconfig_2.0.3        broom_1.0.5            zlibbioc_1.44.0        scales_1.2.1           tzdb_0.4.0            
[26] timechange_0.2.0       generics_0.1.3         farver_2.1.1           IRanges_2.32.0         car_3.1-2             
[31] cachem_1.0.8           withr_2.5.0            BiocGenerics_0.44.0    cli_3.6.1              magrittr_2.0.3        
[36] crayon_1.5.2           evaluate_0.21          R.methodsS3_1.8.2      fansi_1.0.4            textshaping_0.3.6     
[41] tools_4.2.3            data.table_1.14.8      hms_1.1.3              lifecycle_1.0.3        S4Vectors_0.36.2      
[46] munsell_0.5.0          compiler_4.2.3         jquerylib_0.1.4        GenomeInfoDb_1.34.9    systemfonts_1.0.4     
[51] rlang_1.1.1            RCurl_1.98-1.12        rstudioapi_0.15.0      bitops_1.0-7           labeling_0.4.2        
[56] rmarkdown_2.23         gtable_0.3.3           abind_1.4-5            R6_2.5.1               knitr_1.43            
[61] fastmap_1.1.1          bit_4.0.5              utf8_1.2.3             rprojroot_2.0.3        ragg_1.2.5            
[66] stringi_1.7.12         parallel_4.2.3         Rcpp_1.0.11            vctrs_0.6.3            tidyselect_1.2.0      
[71] xfun_0.39             
LS0tCnRpdGxlOiAiVE1CIG9mIHR1bW9ycyBhY3Jvc3MgdW5wYWlyZWQgbG9uZ2l0dWRpbmFsIHNhbXBsZXMgaW4gdGhlIFBCVEEgQ29ob3J0IgphdXRob3I6ICdBbnRvbmlhIENocm9uaSA8Y2hyb25pYUBjaG9wLmVkdT4gYW5kIEpvIEx5bm5lIFJva2l0YSA8cm9raXRhQGNob3AuZWR1PiBmb3IgRDNCJwpkYXRlOiAiMjAyMyIKb3V0cHV0OgogIGh0bWxfbm90ZWJvb2s6CiAgICB0b2M6IFRSVUUKICAgIHRvY19mbG9hdDogVFJVRQotLS0KCiMjIyMgVHVtb3IgZXZvbHV0aW9uIHByb2plY3QgCgojIyMgRGF0YSB1c2VkIApJbiB0aGlzIG5vdGVib29rLCB3ZSBhcmUgdXNpbmcgdGhlIGBwYnRhLnRzdmAgZmlsZSBnZWVucmF0ZWQgYnkgdGhlIGBzYW1wbGUtZGlzdHJpYnV0aW9uLWFuYWx5c2lzYCBtb2R1bGUuCgojIFNldCB1cApgYGB7ciBsb2FkLWxpYnJhcnl9CnN1cHByZXNzUGFja2FnZVN0YXJ0dXBNZXNzYWdlcyh7CiAgbGlicmFyeSh0aWR5dmVyc2UpCiAgbGlicmFyeShyc3RhdGl4KQogIGxpYnJhcnkoZ2dwdWJyKQp9KQpgYGAKCiMjIERpcmVjdG9yaWVzIGFuZCBGaWxlIElucHV0cy9PdXRwdXRzCmBgYHtyIHNldC1kaXItYW5kLWZpbGUtbmFtZXN9CiMgRGV0ZWN0IHRoZSAiLmdpdCIgZm9sZGVyIC0tIHRoaXMgd2lsbCBiZSBpbiB0aGUgcHJvamVjdCByb290IGRpcmVjdG9yeQojIFVzZSB0aGlzIGFzIHRoZSByb290IGRpcmVjdG9yeSB0byBlbnN1cmUgcHJvcGVyIHNvdXJjaW5nIG9mIGZ1bmN0aW9ucyAKIyBubyBtYXR0ZXIgd2hlcmUgdGhpcyBpcyBjYWxsZWQgZnJvbQpyb290X2RpciA8LSBycHJvanJvb3Q6OmZpbmRfcm9vdChycHJvanJvb3Q6Omhhc19kaXIoIi5naXQiKSkKYW5hbHlzaXNfZGlyIDwtIGZpbGUucGF0aChyb290X2RpciwgImFuYWx5c2VzIiwgInRtYi12YWYtbG9uZ2l0dWRpbmFsIikKaW5wdXRfZGlyIDwtIGZpbGUucGF0aChhbmFseXNpc19kaXIsICJpbnB1dCIpCmZpbGVzX2RpciA8LSBmaWxlLnBhdGgocm9vdF9kaXIsICJhbmFseXNlcyIsICJzYW1wbGUtZGlzdHJpYnV0aW9uLWFuYWx5c2lzIiwgInJlc3VsdHMiKQoKIyBJbnB1dCBmaWxlcwpwYnRhX2ZpbGUgPC0gZmlsZS5wYXRoKGZpbGVzX2RpciwgInBidGEudHN2IikgIyBmaWxlIGZyb20gYWRkLXNhbXBsZS1kaXN0cmlidXRpb24gbW9kdWxlCnRtYl9maWxlIDwtIGZpbGUucGF0aChpbnB1dF9kaXIsICJzbnYtbXV0YXRpb24tdG1iLWNvZGluZy50c3YiKQpwYWxldHRlX2ZpbGUgPC0gZmlsZS5wYXRoKHJvb3RfZGlyLCAiZmlndXJlcyIsICJwYWxldHRlcyIsICJ0dW1vcl9kZXNjcmlwdG9yX2NvbG9yX3BhbGV0dGUudHN2IikKCiMgRmlsZSBwYXRoIHRvIHBsb3QgZGlyZWN0b3J5CnBsb3RzX2RpciA8LQogIGZpbGUucGF0aChhbmFseXNpc19kaXIsICJwbG90cyIpCmlmICghZGlyLmV4aXN0cyhwbG90c19kaXIpKSB7CiAgZGlyLmNyZWF0ZShwbG90c19kaXIpCn0KCnNvdXJjZShwYXN0ZTAocm9vdF9kaXIsICIvZmlndXJlcy9zY3JpcHRzL3RoZW1lLlIiKSkKYGBgCgojIyBSZWFkIGluIGRhdGEgYW5kIHByb2Nlc3MKYGBge3IgbG9hZC1wcm9jZXNzLWlucHV0c30KIyBNYWtlIHRoaXMgcmVwcm9kdWNpYmxlCnNldC5zZWVkKDIwMjMpCgojIFJlYWQgaW4gdG1iIGZpbGUgYW5kIHJlbW92ZSBoeXBlcm11dGFudCBzYW1wbGVzCnRtYiA8LSByZWFkcjo6cmVhZF90c3YodG1iX2ZpbGUsIGd1ZXNzX21heCA9IDEwMDAwMCwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lCiAgZmlsdGVyKCF0bWIgPj0gMTApICU+JSAKICBkcGx5cjo6cmVuYW1lKEtpZHNfRmlyc3RfQmlvc3BlY2ltZW5fSUQgPSBUdW1vcl9TYW1wbGVfQmFyY29kZSkgIyBjaGFuZ2UgbmFtZSBvZiB0aGUgYmlvc3BlY2ltZW4gdG8gbWF0Y2ggdGhlIG9uZSBmcm9tIHRoZSBoaXN0b2xvZ2llcyBmaWxlcwoKIyBSZWFkIGluIHBidGEgZmlsZSBhbmQgY3JlYXRlIGRmCmRmIDwtIHJlYWRyOjpyZWFkX3RzdihwYnRhX2ZpbGUsIGd1ZXNzX21heCA9IDEwMDAwMCwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lCiAgZmlsdGVyKCEoZXhwZXJpbWVudGFsX3N0cmF0ZWd5ID09ICJSTkEtU2VxIiksCiAgICAgICAgICEodHVtb3JfZGVzY3JpcHRvciA9PSAiVW5hdmFpbGFibGUiKSkgJT4lICMgdGhlc2UgYXJlIDIgc2FtcGxlcwogIGxlZnRfam9pbih0bWIsIGJ5ID0gYygiS2lkc19GaXJzdF9CaW9zcGVjaW1lbl9JRCIsICJleHBlcmltZW50YWxfc3RyYXRlZ3kiKSkgJT4lCiAgc2VsZWN0KEtpZHNfRmlyc3RfUGFydGljaXBhbnRfSUQsIEtpZHNfRmlyc3RfQmlvc3BlY2ltZW5fSUQsIHR1bW9yX2Rlc2NyaXB0b3IsCiAgICAgICAgIGJyb2FkX2hpc3RvbG9neSwgbWF0Y2hfaWRfRE5BLCBleHBlcmltZW50YWxfc3RyYXRlZ3ksIAogICAgICAgICBjYW5jZXJfZ3JvdXAsIHNob3J0X2hpc3RvbG9neSwgdG1iLCBtdXRhdGlvbl9jb3VudCwgRE5BKSAlPiUKICBkcGx5cjo6Om11dGF0ZShzaG9ydF9oaXN0b2xvZ3lfc3VtID0gaWZlbHNlKHNob3J0X2hpc3RvbG9neSA9PSAiSEdBVCIsICJIR0ciLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHNob3J0X2hpc3RvbG9neSA9PSAiTEdBVCIsICJMR0ciLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBpZmVsc2Uoc2hvcnRfaGlzdG9sb2d5ID09ICJFcGVuZHltb21hIiwgIkVwZW5keW1vbWEiLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHNob3J0X2hpc3RvbG9neSA9PSAiTWVkdWxsb2JsYXN0b21hIiwgIk1lZHVsbG9ibGFzdG9tYSIsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgaWZlbHNlKHNob3J0X2hpc3RvbG9neSA9PSAiQVRSVCIsICJBVFJUIiwgIk90aGVyIikpKSkpLAogICAgICAgICAgICAgICAgIGxvZzEwX3RtYiA9IGFicyhsb2cxMCh0bWIpKSwKICAgICAgICAgICAgICAgICB0dW1vcl9kZXNjcmlwdG9yID0gZmFjdG9yKHR1bW9yX2Rlc2NyaXB0b3IpLAogICAgICAgICAgICAgICAgIHR1bW9yX2Rlc2NyaXB0b3IgPSBmY3RfcmVsZXZlbCh0dW1vcl9kZXNjcmlwdG9yLCBjKCJEaWFnbm9zaXMiLCAiUHJvZ3Jlc3NpdmUiLCAiUmVjdXJyZW5jZSIsICJEZWNlYXNlZCIsICJTZWNvbmQgTWFsaWduYW5jeSIsICJVbmF2YWlsYWJsZSIpKSkgJT4lIAogIGRpc3RpbmN0KG1hdGNoX2lkX0ROQSwgLmtlZXBfYWxsID0gVFJVRSkgJT4lICMga2VlcCBvbmx5IG9uZSBic19zYW1wbGUgcGVyIGdlbm9taWMgYXNzYXkgKFdHUy9XWFMpCiAgZmlsdGVyKCFpcy5uYSh0bWIpKQoKIyBIb3cgbWFueSBzYW1wbGVzIHBlciBUaW1lcG9pbnQ/CnByaW50KGRmICU+JSBjb3VudCh0dW1vcl9kZXNjcmlwdG9yKSkKCiMgSG93IG1hbnkgc2FtcGxlcyBwZXIgY2FuY2VyIHR5cGU/CnByaW50KGRmICU+JSBjb3VudChzaG9ydF9oaXN0b2xvZ3lfc3VtKSkKCiMgSG93IG1hbnkgc2FtcGxlcyBwZXIgVGltZXBvaW50IGFuZCBjYW5jZXIgdHlwZT8KcmVuYW1lKGNvdW50KGRmLCB0dW1vcl9kZXNjcmlwdG9yLCBzaG9ydF9oaXN0b2xvZ3lfc3VtKSwgRnJlcSA9IG4pCgojIEhvdyBtYW55IGNhc2VzIHdpdGggdW5wYWlyZWQgbG9uZ2l0dWRpbmFsIHNhbXBsZXM/Cm5vX3NhbXBsZXMgPC0gbGVuZ3RoKHVuaXF1ZShkZiRLaWRzX0ZpcnN0X1BhcnRpY2lwYW50X0lEKSkKCiMgTGV0J3MgY291bnQgYW5kIHJlbW92ZSBhbnkgdGltZXBvaW50cyB3aXRoIGxlc3MgdGhhbiAyIHNhbXBsZXMgdGhlcmVpbgp0aW1lcG9pbnRfbl9kZiA8LSBkZiAlPiUgCiAgY291bnQodHVtb3JfZGVzY3JpcHRvcikgJT4lIAogIGRwbHlyOjptdXRhdGUodHVtb3JfZGVzY3JpcHRvcl9uID0gZ2x1ZTo6Z2x1ZSgie3R1bW9yX2Rlc2NyaXB0b3J9IChOPXtufSkiKSkgJT4lIAogIGRwbHlyOjpyZW5hbWUodGltZXBvaW50X24gPSBuKQoKZGZfcGxvdCA8LSBkZiAlPiUgCiAgbGVmdF9qb2luKHRpbWVwb2ludF9uX2RmLCBieSA9IGMoInR1bW9yX2Rlc2NyaXB0b3IiKSkgJT4lCiAgZmlsdGVyKCF0aW1lcG9pbnRfbiA8PSAyKSAjIHJlbW92ZSBpZiB0b3RhbCBudW1iZXIgb2YgdmFsdWVzIHBlciBncm91cCBpcyBsZXNzIHRoYW4gMgpgYGAgCgoKIyMgSG93IG1hbnkgcGF0aWVudCBzYW1wbGVzIGluIHRoZSB1bnBhaXJlZCBsb25naXR1ZGluYWwgZGF0YT8KVGhlcmUgYXJlIGByIG5vX3NhbXBsZXNgIHNhbXBsZXMgaW4gdG90YWwuCgojIEFsbCB1bnBhaXJlZCBzYW1wbGVzCldlIGFyZSBpbnRlcmVzdGVkIGluIGhvdyBUTUIgY2hhbmdlcyBvdmVyIHRoZSB0aW1lIGluIGFsbCBQQlRBIHNhbXBsZXMgKHVucGFpcmVkIHNhbXBsZXMpLgoKYGBge3IgZGVmaW5lLXBhcmFtZXRlcnMtZm9yLXBsb3RzfQojIFJlYWQgY29sb3IgcGFsZXR0ZQpwYWxldHRlX2RmIDwtIHJlYWRyOjpyZWFkX3RzdihwYWxldHRlX2ZpbGUsIGd1ZXNzX21heCA9IDEwMDAwMCwgc2hvd19jb2xfdHlwZXMgPSBGQUxTRSkgJT4lIAogIG11dGF0ZSh0dW1vcl9kZXNjcmlwdG9yID0gY29sb3JfbmFtZXMpCgojIERlZmluZSBhbmQgb3JkZXIgcGFsZXR0ZQpwYWxldHRlIDwtIHBhbGV0dGVfZGYkaGV4X2NvZGVzCm5hbWVzKHBhbGV0dGUpIDwtIHBhbGV0dGVfZGYkdHVtb3JfZGVzY3JpcHRvcgoKIyBEZWZpbmUgbGFiZWwgZm9yIHBsb3RzClRpbWVwb2ludCA8LSBkZl9wbG90JHR1bW9yX2Rlc2NyaXB0b3IKCiMgRGVmaW5lIHlsaW0KeWxpbSA8LSBtYXgoZGZfcGxvdCR0bWIpCmBgYAoKYGBge3IgcGxvdC10b3RhbCwgZmlnLndpZHRoID0gMTAsIGZpZy5oZWlnaHQgPSA1LCBmaWcuZnVsbHdpZHRoID0gVFJVRX0KcHJpbnQoZGZfcGxvdCAlPiUgCiAgICAgICAgZ2dwbG90Mjo6Z2dwbG90KCkgKyAKICAgICAgICBnZ3Bsb3QyOjphZXMoeCA9IHR1bW9yX2Rlc2NyaXB0b3IsIAogICAgICAgICAgICAgICAgICAgICB5ID0gdG1iLAogICAgICAgICAgICAgICAgICAgICBjb2xvciA9IFRpbWVwb2ludCkgKyAKICAgICAgICBnZ3Bsb3QyOjpnZW9tX2ppdHRlcih3aWR0aCA9IDAuMiwgYWxwaGEgPSAwLjUsIHNpemUgPSAxLjUpICsgCiAgICAgICAgIyBsaWdodCBndWlkaW5nIGxpbmUgcmVwcmVzZW50aW5nIDAgZXhwb3N1cmUKICAgICAgICBnZ3Bsb3QyOjpnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBzaXplID0gMC4xNSkgKyAKICAgICAgICBnZ3Bsb3QyOjpzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzID0gcGFsZXR0ZSwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGJyZWFrcyA9IHNvcnQobmFtZXMocGFsZXR0ZSkpKSArCiAgICAgICAgZ2dwbG90Mjo6c3RhdF9zdW1tYXJ5KGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDAuMykgKyAKICAgICAgICBnZ3Bsb3QyOjpsYWJzKHggPSAiVHVtb3IgZGVzY3JpcHRvciIsCiAgICAgICAgICAgICAgICAgICAgICB5ID0gIlRNQiIpICsKICAgICAgICB0aGVtZV9QdWJsaWNhdGlvbigpICsKICAgICAgICBzY2FsZV95X2NvbnRpbnVvdXMobGltaXRzID0gYygwLCB5bGltKSkgKwogICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKSkKCiMgU2F2ZSB0aGUgcGxvdApnZ3NhdmUoZmlsZW5hbWUgPSAiVE1CLXVucGFpcmVkLWxvbmdpdHVkaW5hbC1zYW1wbGVzLnBkZiIsCiAgICAgICBwYXRoID0gcGxvdHNfZGlyLCAKICAgICAgIHdpZHRoID0gMTAsIAogICAgICAgaGVpZ2h0ID0gNSwgCiAgICAgICBkZXZpY2UgPSAicGRmIiwgCiAgICAgICB1c2VEaW5nYmF0cyA9IEZBTFNFKQpgYGAKCgojIEFsbCB1bnBhaXJlZCBzYW1wbGVzIGFjcm9zcyBjYW5jZXIgdHlwZXMKV2Ugd2lsbCB1c2UgdGhlIGBzaG9ydF9oaXN0b2xvZ3lgIGNvbHVtbiB0byBkaXNwbGF5IFRNQiBkaWZmZXJlbmNlcyBhY3Jvc3MgY2FuY2VyIHR5cGVzLgoKYGBge3IgcGxvdC1jYW5jZXItZ3JvdXAsIGZpZy53aWR0aCA9IDI1LCBmaWcuaGVpZ2h0ID0gMjAsIGZpZy5mdWxsd2lkdGggPSBUUlVFfQpwcmludChkZl9wbG90ICU+JQogICAgICAgIGdncGxvdDI6OmdncGxvdCgpICsgCiAgICAgICAgZ2dwbG90Mjo6YWVzKHggPSB0dW1vcl9kZXNjcmlwdG9yLCAKICAgICAgICAgICAgICAgICAgICAgeSA9IHRtYiwKICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBUaW1lcG9pbnQpICsgCiAgICAgICAgZ2dwbG90Mjo6Z2VvbV9qaXR0ZXIod2lkdGggPSAwLjIsIGFscGhhID0gMC41LCBzaXplID0gMS41KSArIAogICAgICAgICMgbGlnaHQgZ3VpZGluZyBsaW5lIHJlcHJlc2VudGluZyAwIGV4cG9zdXJlCiAgICAgICAgZ2dwbG90Mjo6Z2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgc2l6ZSA9IDAuMTUpICsgCiAgICAgICAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzb3J0KG5hbWVzKHBhbGV0dGUpKSkgKwogICAgICAgIGdncGxvdDI6OnN0YXRfc3VtbWFyeShjb2xvciA9ICJibGFjayIsIHNpemUgPSAwLjMpICsgCiAgICAgICAgZ2dwbG90Mjo6ZmFjZXRfd3JhcCh+c2hvcnRfaGlzdG9sb2d5LCBucm93ID0gOCkgKwogICAgICAgIGdncGxvdDI6OmxhYnMoeCA9ICJUdW1vciBkZXNjcmlwdG9yIiwKICAgICAgICAgICAgICAgICAgICAgIHkgPSAiVE1CIikgKwogICAgICAgIHRoZW1lX1B1YmxpY2F0aW9uKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkgKwogICAgICAgIHNjYWxlX3lfY29udGludW91cyhsaW1pdHMgPSBjKDAsIHlsaW0pKSkKCiMgU2F2ZSB0aGUgcGxvdApnZ3NhdmUoZmlsZW5hbWUgPSAiVE1CLXVucGFpcmVkLWxvbmdpdHVkaW5hbC1zYW1wbGVzLWNhbmNlci10eXBlLnBkZiIsIAogICAgICAgcGF0aCA9IHBsb3RzX2RpciwgCiAgICAgICB3aWR0aCA9IDI1LCAKICAgICAgIGhlaWdodCA9IDIwLCAKICAgICAgIGRldmljZSA9ICJwZGYiLCAKICAgICAgIHVzZURpbmdiYXRzID0gRkFMU0UpCmBgYAoKV2Ugb2JzZXJ2ZSB0aGF0IG1ham9yaXR5IG9mIHNhbXBsZXMgYXJlIEhpZ2gtIGFuZCBMb3ctZ3JhZGUgZ2xpb21hcyBhcyB3ZWxsIGFzIEVwZW5keW1vbWEsIHNvIHdlIHdpbGwgY2xhc3NpZnkgYWNjb3JkaW5nbHkgKHZlcnN1cyBhbnkgb3RoZXIgY2FuY2VyIHR5cGVzKS4KCiMgQWxsIHVucGFpcmVkIHNhbXBsZXMgYWNyb3NzIGNhbmNlciB0eXBlcyBzdW1tYXJpemVkCgpgYGB7ciBwbG90LWNhbmNlci1ncm91cC1zdW0sIGZpZy53aWR0aCA9IDEyLCBmaWcuaGVpZ2h0ID0gNiwgZmlnLmZ1bGx3aWR0aCA9IFRSVUV9CiMgTGV0J3MgY291bnQgYW5kIHJlbW92ZSBhbnkgY2FuY2VyIHR5cGVzIGFuZCB0aW1lcG9pbnRzIHdpdGggbGVzcyB0aGFuIDIgc2FtcGxlcyB0aGVyZWluCnR1bW9yX2Rlc2NyaXB0b3JfY2FuY2VyX25fZGYgPC0gZGZfcGxvdCAlPiUgCiAgY291bnQoc2hvcnRfaGlzdG9sb2d5X3N1bSwgdHVtb3JfZGVzY3JpcHRvcikgJT4lIAogIGRwbHlyOjptdXRhdGUodHVtb3JfZGVzY3JpcHRvcl9jYW5jZXJfbiA9IGdsdWU6OmdsdWUoIntzaG9ydF9oaXN0b2xvZ3lfc3VtfV97dHVtb3JfZGVzY3JpcHRvcn0gIChOPXtufSkiKSkgJT4lIAogIGRwbHlyOjpyZW5hbWUoaGlzdG9sb2d5X24gPSBuKQoKZGZfcGxvdF9jYW5jZXIgPC0gZGZfcGxvdCAlPiUgCiAgbGVmdF9qb2luKHR1bW9yX2Rlc2NyaXB0b3JfY2FuY2VyX25fZGYsIGJ5ID0gYygidHVtb3JfZGVzY3JpcHRvciIsICJzaG9ydF9oaXN0b2xvZ3lfc3VtIikpICU+JQogIGZpbHRlcighaGlzdG9sb2d5X24gPD0gMikgIyByZW1vdmUgaWYgdG90YWwgbnVtYmVyIG9mIHZhbHVlcyBwZXIgZ3JvdXAgaXMgbGVzcyB0aGFuIDIKCiMgRGVmaW5lIGxhYmVsIGZvciBwbG90cwpUaW1lcG9pbnRfY2FuY2VyIDwtIGRmX3Bsb3RfY2FuY2VyJHR1bW9yX2Rlc2NyaXB0b3IKCiMgRGVmaW5lIHlsaW0KeWxpbV9jYW5jZXIgPC0gbWF4KGRmX3Bsb3RfY2FuY2VyJHRtYikKCiMgUGxvdCB0aGUgcGxvdCEKcHJpbnQoZGZfcGxvdF9jYW5jZXIgJT4lIAogICAgICAgIGdncGxvdDI6OmdncGxvdCgpICsgCiAgICAgICAgZ2dwbG90Mjo6YWVzKHggPSB0dW1vcl9kZXNjcmlwdG9yLCAKICAgICAgICAgICAgICAgICAgICAgeSA9IHRtYiwKICAgICAgICAgICAgICAgICAgICAgY29sb3IgPSBUaW1lcG9pbnRfY2FuY2VyKSArIAogICAgICAgIGdncGxvdDI6Omdlb21faml0dGVyKHdpZHRoID0gMC4yLCBhbHBoYSA9IDAuNSwgc2l6ZSA9IDEuNSkgKyAKICAgICAgICAjIGxpZ2h0IGd1aWRpbmcgbGluZSByZXByZXNlbnRpbmcgMCBleHBvc3VyZQogICAgICAgIGdncGxvdDI6Omdlb21faGxpbmUoeWludGVyY2VwdCA9IDAsIHNpemUgPSAwLjE1KSArIAogICAgICAgIGdncGxvdDI6OnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc29ydChuYW1lcyhwYWxldHRlKSkpICsKICAgICAgICBnZ3Bsb3QyOjpzdGF0X3N1bW1hcnkoY29sb3IgPSAiYmxhY2siLCBzaXplID0gMC4zKSArIAogICAgICAgIGdncGxvdDI6OmZhY2V0X3dyYXAofnNob3J0X2hpc3RvbG9neV9zdW0sIG5yb3cgPSAxKSArCiAgICAgICAgZ2dwbG90Mjo6bGFicyh4ID0gIlR1bW9yIGRlc2NyaXB0b3IiLAogICAgICAgICAgICAgICAgICAgICAgeSA9ICJUTUIiKSArCiAgICAgICAgdGhlbWVfUHVibGljYXRpb24oKSArIAogICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKSArCiAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgeWxpbV9jYW5jZXIpKSkKCiMgU2F2ZSB0aGUgcGxvdApnZ3NhdmUoZmlsZW5hbWUgPSAiVE1CLXVucGFpcmVkLWxvbmdpdHVkaW5hbC1zYW1wbGVzLWNhbmNlci10eXBlLXN1bS5wZGYiLCAKICAgICAgIHBhdGggPSBwbG90c19kaXIsIAogICAgICAgd2lkdGggPSAxMiwgCiAgICAgICBoZWlnaHQgPSA2LCAKICAgICAgIGRldmljZSA9ICJwZGYiLCAKICAgICAgIHVzZURpbmdiYXRzID0gRkFMU0UpCgoKIyBQbG90IGJ5IHVzaW5nIHR1bW9yX2Rlc2NyaXB0b3JfY2FuY2VyX24KIyBMZXQncyBvcmRlciBmaXJzdCB4IGF4aXMgCiNUT0RPOiBUbyBtYWtlIHRoZSBmIHJlcHJvZHVjaWJsZQpmID0gYygiQVRSVF9EaWFnbm9zaXMgIChOPTQ4KSIsICJBVFJUX1Byb2dyZXNzaXZlICAoTj0xMCkiLCAiQVRSVF9SZWN1cnJlbmNlICAoTj0zKSIsICJBVFJUX0RlY2Vhc2VkICAoTj00KSIsCiAgIkVwZW5keW1vbWFfRGlhZ25vc2lzICAoTj0xMTMpIiwgIkVwZW5keW1vbWFfUHJvZ3Jlc3NpdmUgIChOPTIwKSIgLCAiRXBlbmR5bW9tYV9SZWN1cnJlbmNlICAoTj0yNCkiLCAiRXBlbmR5bW9tYV9EZWNlYXNlZCAgKE49NykiLAogICAgICAiSEdHX0RpYWdub3NpcyAgKE49MjM1KSIsICJIR0dfUHJvZ3Jlc3NpdmUgIChOPTIyKSIsICJIR0dfUmVjdXJyZW5jZSAgKE49MTUpIiwgIkhHR19EZWNlYXNlZCAgKE49NzIpIiwgIkhHR19TZWNvbmQgTWFsaWduYW5jeSAgKE49NSkiLAogICAgICAiTEdHX0RpYWdub3NpcyAgKE49NDA1KSIgLCAiTEdHX1Byb2dyZXNzaXZlICAoTj02MSkiLCAiTEdHX1JlY3VycmVuY2UgIChOPTI1KSIsICJMR0dfRGVjZWFzZWQgIChOPTcpIiwgIkxHR19TZWNvbmQgTWFsaWduYW5jeSAgKE49NCkiICwKICAgICAgIk1lZHVsbG9ibGFzdG9tYV9EaWFnbm9zaXMgIChOPTIxNykiLCAiTWVkdWxsb2JsYXN0b21hX1Byb2dyZXNzaXZlICAoTj02KSIsICJNZWR1bGxvYmxhc3RvbWFfUmVjdXJyZW5jZSAgKE49NikiICwgIk1lZHVsbG9ibGFzdG9tYV9EZWNlYXNlZCAgKE49NikiLAogICAgICAiT3RoZXJfRGlhZ25vc2lzICAoTj01MzgpIiwgIk90aGVyX1Byb2dyZXNzaXZlICAoTj04OSkiLCAiT3RoZXJfUmVjdXJyZW5jZSAgKE49ODApIiwgIk90aGVyX0RlY2Vhc2VkICAoTj04KSIpCgpkZl9wbG90X2NhbmNlciA8LSBkZl9wbG90X2NhbmNlciAlPiUgCiAgbXV0YXRlKHR1bW9yX2Rlc2NyaXB0b3JfY2FuY2VyX24gPSBmYWN0b3IodHVtb3JfZGVzY3JpcHRvcl9jYW5jZXJfbiksCiAgICAgICAgICAgICAgICAgdHVtb3JfZGVzY3JpcHRvcl9jYW5jZXJfbiA9IGZjdF9yZWxldmVsKHR1bW9yX2Rlc2NyaXB0b3JfY2FuY2VyX24sIGYpKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAKIyBQbG90IHRoZSBwbG90IQpwcmludChkZl9wbG90X2NhbmNlciAlPiUgCiAgICAgICAgZ2dwbG90Mjo6Z2dwbG90KCkgKyAKICAgICAgICBnZ3Bsb3QyOjphZXMoeCA9IHR1bW9yX2Rlc2NyaXB0b3JfY2FuY2VyX24sIAogICAgICAgICAgICAgICAgICAgICB5ID0gdG1iLAogICAgICAgICAgICAgICAgICAgICBjb2xvciA9IFRpbWVwb2ludF9jYW5jZXIpICsgCiAgICAgICAgZ2dwbG90Mjo6Z2VvbV9qaXR0ZXIod2lkdGggPSAwLjIsIGFscGhhID0gMC41LCBzaXplID0gMS41KSArIAogICAgICAgICMgbGlnaHQgZ3VpZGluZyBsaW5lIHJlcHJlc2VudGluZyAwIGV4cG9zdXJlCiAgICAgICAgZ2dwbG90Mjo6Z2VvbV9obGluZSh5aW50ZXJjZXB0ID0gMCwgc2l6ZSA9IDAuMTUpICsgCiAgICAgICAgZ2dwbG90Mjo6c2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcyA9IHBhbGV0dGUsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBicmVha3MgPSBzb3J0KG5hbWVzKHBhbGV0dGUpKSkgKwogICAgICAgIGdncGxvdDI6OnN0YXRfc3VtbWFyeShjb2xvciA9ICJibGFjayIsIHNpemUgPSAwLjMpICsgCiAgICAgICAgZ2dwbG90Mjo6bGFicyh4ID0gIlR1bW9yIGRlc2NyaXB0b3IiLAogICAgICAgICAgICAgICAgICAgICAgeSA9ICJUTUIiKSArCiAgICAgICAgdGhlbWVfUHVibGljYXRpb24oKSArIAogICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gOTApKSArCiAgICAgICAgc2NhbGVfeV9jb250aW51b3VzKGxpbWl0cyA9IGMoMCwgeWxpbV9jYW5jZXIpKSkKCiMgU2F2ZSB0aGUgcGxvdApnZ3NhdmUoZmlsZW5hbWUgPSAiVE1CLXVucGFpcmVkLWxvbmdpdHVkaW5hbC1zYW1wbGVzLWNhbmNlci10eXBlLXN1bS1uLnBkZiIsIAogICAgICAgcGF0aCA9IHBsb3RzX2RpciwgCiAgICAgICB3aWR0aCA9IDEyLCAKICAgICAgIGhlaWdodCA9IDYsIAogICAgICAgZGV2aWNlID0gInBkZiIsIAogICAgICAgdXNlRGluZ2JhdHMgPSBGQUxTRSkKCiNUT0RPOiBUbyBjaG9vc2Ugb25lIG9mIHRoZSBwbG90cyBpbiB0aGUgY29kZSBjaHVuayBgcGxvdC1jYW5jZXItZ3JvdXAtc3VtYApgYGAKCiMgU3VtbWFyeSBzdGF0aXN0aWNzIGZvciBUaW1lcG9pbnRzIGFuZCBjYW5jZXIgdHlwZXMKQ29uc2lkZXJpbmcgdGhlIGluZXF1YWxpdGllcyBpbiB0aGUgc2FtcGxpbmcgZWZmb3J0IGZvciBlYWNoIHRpbWVwb2ludCwgbGV0J3MgZXhwbG9yZSB3aGV0aGVyIHRoZSBzYW1wbGluZyBzaXplIGFmZmVjdHMgdGhlIG9ic2VydmVkIHBhdHRlcm5zLCBlLmcuLCBpbmRpY2F0aW9uIG9mIFByb2dyZXNzaXZlIGFuZCBSZWN1cnJlbmNlIGhhdmluZyBoaWdlciBUTUIgY29tcGFyZWQgdG8gRGlhZ25vc2lzIGZvciBIaWdoLWdyYWRlIGdsaW9tYSBwYXRpZW50cy4KCmBgYHtyIHN1bW1hcnktc3RhdGlzdGljcywgZmlnLndpZHRoID0gMTIsIGZpZy5oZWlnaHQgPSA2LCBmaWcuZnVsbHdpZHRoID0gVFJVRX0KIyBJbnNwZWN0IHNvbWUgcmFuZG9tIHJvd3Mgb2YgdGhlIGRhdGEgYnkgZ3JvdXBzCnNldC5zZWVkKDIwMjMpCmRmX3Bsb3RfY2FuY2VyICU+JSAKICBzZWxlY3Qoc2hvcnRfaGlzdG9sb2d5X3N1bSwgdHVtb3JfZGVzY3JpcHRvciwgdG1iLCBsb2cxMF90bWIpICU+JSAKICBzYW1wbGVfbl9ieShzaG9ydF9oaXN0b2xvZ3lfc3VtLCB0dW1vcl9kZXNjcmlwdG9yLCB0bWIsIHNpemUgPSAxKQoKIyBDb21wdXRlIHNvbWUgc3VtbWFyeSBzdGF0aXN0aWNzIChtZWFuIGFuZCBzZCkgYnkgZ3JvdXBzOgpzdGF0LnN1bW1hcnkgPC0gZGZfcGxvdF9jYW5jZXIgJT4lCiAgZ3JvdXBfYnkoc2hvcnRfaGlzdG9sb2d5X3N1bSwgdHVtb3JfZGVzY3JpcHRvcikgJT4lCiAgZ2V0X3N1bW1hcnlfc3RhdHModG1iLCB0eXBlID0gIm1lYW5fc2QiKQpzdGF0LnN1bW1hcnkKCiMgUGFpcndpc2UgY29tcGFyaXNvbnMgYmV0d2VlbiB0aW1lIHBvaW50cyBhdCBlYWNoIGdyb3VwIGxldmVscwojIFBhaXJlZCB0LXRlc3QgaXMgdXNlZCBiZWNhdXNlIHdlIGhhdmUgcmVwZWF0ZWQgbWVhc3VyZXMgYnkgdGltZQpzdGF0LnRlc3QgPC0gZGZfcGxvdF9jYW5jZXIgJT4lCiAgZ3JvdXBfYnkoc2hvcnRfaGlzdG9sb2d5X3N1bSkgJT4lCiAgcGFpcndpc2VfdF90ZXN0KGxvZzEwX3RtYiB+IHR1bW9yX2Rlc2NyaXB0b3IsIAogICAgICAgICAgICAgICAgICBwYWlyZWQgPSBGQUxTRSwgCiAgICAgICAgICAgICAgICAgIHAuYWRqdXN0Lm1ldGhvZCA9ICJib25mZXJyb25pIikKc3RhdC50ZXN0CgojIEFkZCBzdGF0aXN0aWNhbCB0ZXN0IHAtdmFsdWVzCnN0YXQudGVzdCA8LSBzdGF0LnRlc3QgJT4lIGFkZF94eV9wb3NpdGlvbih4ID0gInR1bW9yX2Rlc2NyaXB0b3IiKQoKIyBDcmVhdGUgYnhwCnByaW50KGdnYm94cGxvdChkZl9wbG90X2NhbmNlciwKICAgICAgICAgICAgICAgIHggPSAidHVtb3JfZGVzY3JpcHRvciIsCiAgICAgICAgICAgICAgICB5ID0gImxvZzEwX3RtYiIsCiAgICAgICAgICAgICAgICBjb2xvciA9ICJ0dW1vcl9kZXNjcmlwdG9yIiwKICAgICAgICAgICAgICAgIHBhbGV0dGUgPSBwYWxldHRlKSArCiAgICAgICAgZmFjZXRfd3JhcCh+c2hvcnRfaGlzdG9sb2d5X3N1bSwgbnJvdyA9IDEpICsKICAgICAgICB0aGVtZV9QdWJsaWNhdGlvbigpICsgCiAgICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpICsKICAgICAgICBzdGF0X3B2YWx1ZV9tYW51YWwoc3RhdC50ZXN0LCBsYWJlbCA9ICJwLmFkai5zaWduaWYiLAogICAgICAgICAgICAgICAgICAgICAgICAgICBzdGVwLmluY3JlYXNlID0gMC4wOCwgaGlkZS5ucyA9IFRSVUUsIHRpcC5sZW5ndGggPSAwKSkKCiMgU2F2ZSB0aGUgcGxvdApnZ3NhdmUoZmlsZW5hbWUgPSAiVE1CLUJ4cC1zdGF0LXRlc3QucGRmIiwgCiAgICAgICBwYXRoID0gcGxvdHNfZGlyLCAKICAgICAgIHdpZHRoID0gMTIsIAogICAgICAgaGVpZ2h0ID0gNiwgCiAgICAgICBkZXZpY2UgPSAicGRmIiwgCiAgICAgICB1c2VEaW5nYmF0cyA9IEZBTFNFKQoKCiMgQ3JlYXRlIGppdHRlciBwbG90CnByaW50KGRmX3Bsb3RfY2FuY2VyICU+JSAKICAgICAgICBnZ3Bsb3QyOjpnZ3Bsb3QoKSArIAogICAgICAgIGdncGxvdDI6OmFlcyh4ID0gdHVtb3JfZGVzY3JpcHRvciwgCiAgICAgICAgICAgICAgICAgICAgIHkgPSBsb2cxMF90bWIsCiAgICAgICAgICAgICAgICAgICAgIGNvbG9yID0gVGltZXBvaW50X2NhbmNlcikgKyAKICAgICAgICBnZ3Bsb3QyOjpnZW9tX2ppdHRlcih3aWR0aCA9IDAuMiwgYWxwaGEgPSAwLjUsIHNpemUgPSAxLjUpICsgCiAgICAgICAgIyBsaWdodCBndWlkaW5nIGxpbmUgcmVwcmVzZW50aW5nIDAgZXhwb3N1cmUKICAgICAgICBnZ3Bsb3QyOjpnZW9tX2hsaW5lKHlpbnRlcmNlcHQgPSAwLCBzaXplID0gMC4xNSkgKwogICAgICAgIGdncGxvdDI6OnNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXMgPSBwYWxldHRlLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgYnJlYWtzID0gc29ydChuYW1lcyhwYWxldHRlKSkpICsKICAgICAgICBmYWNldF93cmFwKH5zaG9ydF9oaXN0b2xvZ3lfc3VtLCBucm93ID0gMSkgKwogICAgICAgIHRoZW1lX1B1YmxpY2F0aW9uKCkgKyAKICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwKSkgKwogICAgICAgIHN0YXRfcHZhbHVlX21hbnVhbChzdGF0LnRlc3QsIGxhYmVsID0gInAuYWRqLnNpZ25pZiIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIHN0ZXAuaW5jcmVhc2UgPSAwLjA4LCBoaWRlLm5zID0gVFJVRSwgdGlwLmxlbmd0aCA9IDApKQoKIyBTYXZlIHRoZSBwbG90Cmdnc2F2ZShmaWxlbmFtZSA9ICJUTUItaml0dGVyLXN0YXQtdGVzdC5wZGYiLCAKICAgICAgIHBhdGggPSBwbG90c19kaXIsIAogICAgICAgd2lkdGggPSAxMiwgCiAgICAgICBoZWlnaHQgPSA2LCAKICAgICAgIGRldmljZSA9ICJwZGYiLCAKICAgICAgIHVzZURpbmdiYXRzID0gRkFMU0UpCgojIFRoaXMgY29kZSB3YXMgaW5zcGlyZWQgYnkgdGhlIGZvbGxvd2luZzoKIyBIT1cgVE8gUEVSRk9STSBNVUxUSVBMRSBQQUlSRUQgVC1URVNUUyBJTiBSCiMgaHR0cHM6Ly93d3cuZGF0YW5vdmlhLmNvbS9lbi9ibG9nL2hvdy10by1wZXJmb3JtLW11bHRpcGxlLXBhaXJlZC10LXRlc3RzLWluLXIvCgojVE9ETzogVG8gY2hvb3NlIG9uZSBvZiB0aGUgcGxvdHMgaW4gdGhpcyBjb2RlIGNodW5rIGBzdW1tYXJ5LXN0YXRpc3RpY3NgCmBgYAoKYGBge3IgZWNobz1UUlVFfQpzZXNzaW9uSW5mbygpCmBgYAo=